/**
 *  @file KeyValueListT.h
 */
#ifndef _KEYVALUELISTT_H_
#define _KEYVALUELISTT_H_

#include "../common/CppMemPool.h"
#include "KVPairT.h"
#include "ListT.h"
#include "../text/CFString.h"

namespace cppflib
{

namespace collections
{

/**
 *  A list of key-value pairs (key and value are BaseObject derived object pointers)
 *  This one isn't the same as LinkedHashtableT -- duplicated keys are allowed
 */
template <class KEYT, class VALT>
class KeyValueListT : public BaseObject, public ICollection
{
private:
   ListCppObjT<KVPairT<KEYT, VALT> > * pKVList;

public:
   KeyValueListT(void)
   {
      pKVList = new ListCppObjT<KVPairT<KEYT, VALT> >();
      cppmempool::Retain(pKVList);
   }
    
   virtual ~KeyValueListT(void)
   {
      cppmempool::Release(pKVList);
   }

   /**
    *  Add element to tail
    */
   void AddTail(KEYT *pKey, VALT *pVal)
   {
      pKVList->AddTail(new KVPairT<KEYT, VALT>(pKey, pVal));
   }

   /**
    *  Add element to head
    */
   void AddHead(KEYT *pKey, VALT *pVal)
   {
      pKVList->AddHead(new KVPairT<KEYT, VALT>(pKey, pVal));
   }

   /**
    *  Insert element at a particular position (zero based)
    */
   void Insert(int nIndex, KEYT *pKey, VALT *pVal)
   {
      pKVList->Insert(nIndex, new KVPairT<KEYT, VALT>(pKey, pVal));  
   }

   /**
    *  Remove an element by index
    */
   void RemoveAt(int nIndex)
   {
      pKVList->RemoveAt(nIndex);
   }

   /** 
    *  Remove elements with specified key
    *   
    *  @return number of elements removed
    */
   u32_t RemoveByKey(const KEYT &key)
   {
      u32_t nrRemoved = 0;
      for (int i = 0; i < static_cast<int>(pKVList->GetCount());  ) {
         KVPairT<KEYT, VALT> * pEle = pKVList->Get(i);
         if (pEle->GetKey()->Equals(key)) {  
            RemoveAt(i);
            ++nrRemoved;
         }
         else {
            ++i;
         }
      }
 
      return nrRemoved;
   }

   /** 
    *  Remove elements with specified value
    *   
    *  @return number of elements removed
    */
   u32_t RemoveByValue(const VALT &val)
   {
      u32_t nrRemoved = 0;
      for (int i = 0; i < static_cast<int>(pKVList->GetCount());  ) {
         KVPairT<KEYT, VALT> * pEle = pKVList->Get(i);
         if (pEle->GetVal()->Equals(val)) {  
            RemoveAt(i);
            ++nrRemoved;
         }
         else {
            ++i;
         }
      }
 
      return nrRemoved;
   }

   /**
    *  Remove all elements
    */
   void Clear()
   {
      while (pKVList->GetCount() > 0) {
         RemoveAt(0);
      }
   }

   /**
    *  Get both key and value based on index (zero based)
    */
   void Get(int nIndex, KEYT *& pKey, VALT *& pVal) const
   {
      KVPairT<KEYT, VALT> * pEle = pKVList->Get(nIndex);
      pKey = pEle->GetKey();
      pVal = pEle->GetVal();
   }

   /**
    *  Get key only
    */
   KEYT * GetKey(int nIndex) const
   {
      KVPairT<KEYT, VALT> * pEle = pKVList->Get(nIndex);
      return pEle->GetKey();
   }

   /**
    *  Get value only
    */
   VALT * GetVal(int nIndex) const
   {
      KVPairT<KEYT, VALT> * pEle = pKVList->Get(nIndex);
      return pEle->GetVal();
   }

   /**
    *  Get number of element in the list
    */
   u32_t GetCount() const
   {
      return pKVList->GetCount();
   }

   /**
    *  Replace an existing value
    */
   void Set(int nIndex, KEYT* newKey, VALT* newVal)
   {
      pKVList->Set(nIndex, new KVPairT<KEYT, VALT>(newKey, newVal));
   }

   /**
    *  Make a copy of this list -- elements are just shallow copy
    */
   KeyValueListT<KEYT, VALT> * Copy() const
   {
      KeyValueListT<KEYT, VALT> * pCopyList = new KeyValueListT<KEYT, VALT>();
      KEYT *pKey;
      VALT *pVal;
      for (int i = 0; i < static_cast<int>(pKVList->GetCount()); ++i) {
         this->Get(i, pKey, pVal);
         pCopyList->AddTail(pKey, pVal);
      }

      return pCopyList;
   }

   /**
    *  Swap element of 2 slots
    *  @implements ICollection::Swap
    */
   virtual void Swap(int i_1, int i_2)
   {
      pKVList->Swap(i_1, i_2);
   }
    /**
     *  Retrieve ith pointer to the element  
     *  @implements ICollection::Element
     *
     *  @note this return key only as this key value list only support sorting by keys
     */
    virtual ptrany_t Element(int i)
    {
       return reinterpret_cast<ptrany_t>(GetKey(i));
    }

    /**
     *  Sort all elements by key
     */
    void SortByKey(const sort::SortCmpFunc &cmpFunc)
    {
       sort::HeapSort(*this, 0, static_cast<int>(this->GetCount()), cmpFunc);
    }

    /**
     *  Sort partial elements by key
     */
    void SortByKey(int startIndex, int count, const sort::SortCmpFunc &cmpFunc)
    {
       sort::HeapSort(*this, startIndex, count, cmpFunc);
    }
};


//! A useful list alias
typedef KeyValueListT<CFString, CFString> NameValueList;


} // end of namespace collections


} // end of namespace cppflib


#endif
